#!usr/bin/env python3
# -*- coding:utf-8 -*-

#编写MVC,handlers属于V的部分


import re,time,json,logging,hashlib,base64,asyncio
import markdown2

from apis import APIValueError,APIError,Page
from aiohttp import web
from day5_coroweb import get,post
from day4_models import User,Comment,Blog,next_id
from day6_config import configs

COOKIE_NAME = 'awesession'
DISPLAY_PSW = '******'
_COOKIE_KEY = configs.session.secret

#验证邮箱的正则
_RE_EMAIL = re.compile(r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$')
#验证sha1加密后的密码
_RE_SHA1  = re.compile(r'^[0-9a-f]{40}$')


def check_admin(request):
	user = request.__user__
	if user is None or not user.admin:
		raise APIPermissionnError()
def get_page_index(page_str):
	p = 1
	try:
		p = int(page_str)
	except ValueError as e:
		pass
	if p<1:
		p = 1
	return p
def text2html(text):
	lines = map(lambda s: '<p>%s</p>' % s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;'), filter(lambda s: s.strip() != '', text.split('\n')))
	return "".join(lines) #把数组转换成字符串

#根据用户信息生成cookie串
def user2cookie(user,max_age):
	expires = str(int(time.time()+max_age))
	s = '%s-%s-%s-%s' % (user.id,user.passwd,expires,_COOKIE_KEY)
	L = [user.id,expires,hashlib.sha1(s.encode('utf-8')).hexdigest()]
	return '-'.join(L)

#把cookie转换成用户数据
async def cookie2user(coookie_str):
	if not coookie_str:
		return None
	try:
		L = coookie_str.split('-')
		if len(L)!=3:
			return None
		uid,expires,sha1 = L
		if int(expires) < time.time():#过期的cookie
			return None
		user = await User.find(uid)
		if not user:
			return None
		s = '%s-%s-%s-%s' % (uid, user.passwd, expires, _COOKIE_KEY)
		if sha1 !=hashlib.sha1(s.encode('utf-8')).hexdigest():
			logging.info('invalid sha1')
			return None
		user.passwd = DISPLAY_PSW
		return user
	except Exception as e:
		logging.excepttion(e)

def getCookie(user):
	r = web.Response()
	r.set_cookie(COOKIE_NAME,user2cookie(user,86400),max_age=86400,httponly=True)
	user.passwd = DISPLAY_PSW
	r.content_type = 'application/json'
	r.body = json.dumps(user,ensure_ascii=False).encode('utf-8')
	return r
def getSha1Passwd(uid,passwd):
	sha1_passwd = '%s:%s'%(uid,passwd)	
	sha1_passwd = sha1_passwd.encode('utf-8')
	sha1Str = hashlib.sha1(sha1_passwd).hexdigest()	
	return sha1Str

@get('/')
async def index(request):
	summary='happy everyday day,joy coding'
	blogs = await Blog.findAll()	
	if not blogs:
		blogs = []
	return {
		'__template__':'blogs.html',			
		'blogs':blogs
	}

# ------------- 用户注册与登录相关 -----------------

@get('/api/users')
async def api_get_users():#获取所有用户信息
	logging.info('get_users API runing....')
	users = await User.findAll(ordyby='created_at desc')	
	for u in users:
		u.passwd = DISPLAY_PSW	
	return dict(users=users)

@get('/register')
async def register():#跳转到注册页面
	return {
		'__template__':'register.html'
	}
@get('/signin')
async def signin():#跳转到登录页面
	return {
		'__template__':'signin.html'
	}

@get('/signout')
async def signout(request):
	referer = request.headers.get('Referer')
	r= web.HTTPFound(referer or '/')
	r.set_cookie(COOKIE_NAME,'-deleted-',max_age=0,httponly=True)
	logging.info('user signed out.')
	return r

#注册用户
@post('/api/users')
async def api_register_user(*,email,name,passwd):
	if name:
		name = name.strip() #去掉空白
		pass
	if not name:
		raise APIValueError('name')
	if not email or not _RE_EMAIL.match(email):
		raise APIValueError('email')
	if not passwd or not _RE_SHA1.match(passwd):
		raise APIValueError("passwd")

	#验证邮箱是否已经注册	
	users = await User.findAll('email=?',[email])
	if len(users)>0:
		raise APIError('register fail:','email','Email is already in use')
	uid = next_id()	
	sha1Str = getSha1Passwd(uid,passwd)
	imgUrl = 'http://www.gravatar.com/avatar/%s?d=mm&s=120' % hashlib.md5(email.encode('utf-8')).hexdigest()
	user = User(id=uid,name=name,email=email,passwd=sha1Str,image=imgUrl)
	await user.save()
	r = getCookie(user)	
	return r
@post('/api/authenticate')
async def authenticate(*,email,passwd):
	if not email:
		raise APIValueError('email','Ivalid email')
	if not passwd:
		raise APIValueError('email','no password')
	users = await User.findAll('email=?',[email])
	if len(users)==0: #验证用户是否存在
		raise APIValueError('email','Email not exist')
	user = users[0]
	#验证输入的密码是否正确	
	passwd = getSha1Passwd(user.id,passwd)		
	if user.passwd!=passwd:
		raise APIValueError('passwd','Invalid password')
	r = getCookie(user)	
	return r

@get('/manage/users')
def manage_user(*,page='1'): #用户列表页
	return {
		'__template__':'manage_users.html',
		"page_index":get_page_index(page)

	}

# -------------- 博客创建删除修改相关 -------------
@get('/manage/blogs/create')
def manage_create_blog():#创建博客页面
	logging.info("--------------------------manage_create_blog")
	return {
		"__template__":'manage_blog_edit.html',
		"id":"",
		"action":"/api/blogs"
	}

@get('/manage/blogs/edit')
def manage_create_edit(*,id):#修改博客的页面
	logging.info("--------------------------manage_create_edit")
	return {
		"__template__":'manage_blog_edit.html',
		"id":id,
		"action":"/api/blogs%s"%id
	}

@get("/api/blogs/{id}")
async def api_get_blog(*,id): #获取某篇博客
	blog = await Blog.find(id)
	return blog

#创建博客，写入数据库
@post("/api/blogs")
async def api_create_blog(request,*,name,summary,content): 
	check_admin(request)
	if not name or not name.strip():
		raise APIValueError("name","name connot be empty!")
	if not summary or not summary.strip():
		raise APIValueError("summary","summary connot be empty!")
	if not content or not content.strip():
		raise APIValueError("content","content connot be empty!")
	user = request.__user__
	blog = Blog(user_id=user.id,user_name=user.name,user_image=user.image,name=name.strip(),summary=summary.strip(),content=content.strip())
	await blog.save()
	return blog

#博客展示页面
@get('/blog/{id}')
async def get_blog(id):
	blog = await Blog.find(id)
	if not blog:
		raise APIResourceNotFoundError('get_blog:Blog')
	comments = await Comment.findAll('blog_id=?',[id],orderBy='created_at desc')
	for c in comments:
		c.html_content = text2html(c.content)
	blog.html_content = markdown2.markdown(blog.content)
	return {
		"__template__":"blog.html",
		'blog':blog,
		'comments':comments
	}

@post('/api/blogs/{id}')
async def api_update_blog(id,request,*,name,summary,content): #修改博客
	check_admin(request)
	blog = await Blog.find(id)
	if not blog:
		raise APIResourceNotFoundError('Blog')
	if not name or not name.strip():
		raise APIValueError("name","name connot be empty!")
	if not summary or not summary.strip():
		raise APIValueError("summary","summary connot be empty!")
	if not content or not content.strip():
		raise APIValueError("content","content connot be empty!")
	blog.name = name
	blog.summary = summary
	blog.content = content
	await blog.update()
	return blog

@post('/api/blogs/{id}/delete')
async def api_delete_blog(id,request):#删除博客
	check_admin(request)
	blog = Blog.find(id)
	if not blog:
		raise APIResourceNotFoundError('api_delete_blog:blog')
	await blog.remove()
	return dict(id=id)

@get("/api/blogs")
async def api_blogs(*,page='1'): #获取所有博客
	logging.info('api_blogs:%s=>' % page)
	page_index = get_page_index(page)
	num = await Blog.findNumber('count(id)')
	p = Page(num,page_index)
	if num==0:
		return dict(page=p,blogs=())
	blogs = await Blog.findAll(orderBy="created_at desc",limit=(p.offset,p.limit))
	return dict(page=p,blogs=blogs)

@get("/manage/blogs")
def manage_blogs(*,page='1'):#所有博客展示页面
	page_index = get_page_index(page)	
	return {
		"__template__":"manage_blogs.html",
		"page_index":page_index
	}
	
# -------------- 评论区相关 -------------
@get("/api/comments")
async def  api_comments(*,page=1): #获取某一篇博客的所有评论
	page_index = get_page_index(page)
	num = await Comment.findNumber('count(id)')
	p = Page(num,page_index)
	if not num:
		return dict(page=p,comments=())
	comments = await Comment.findAll(orderBy='created_at desc',limit=(p.offset,p.limit))
	return dict(page=p,comments=comments)

@post('/api/blogs/{id}/comments')
async def api_create_comment(id,request,*,content): #评论某篇博客
	user = request.__user__
	if not user:
		raise APIPermissionnError("Please sigin first")
	if not content or not content.strip():
		raise APIValueError("content")
	blog = await Blog.find(id)
	if not blog:
		raise APIResourceNotFoundError('Blog')
	comment = Comment(blog_id=id,user_id=user.id,user_name=user.name,user_image=user.image,content=content.strip())
	await comment.save()
	return comment
@post('/api/comments/{id}/delete')
async def api_delete_comment(id,request):#删除评论
	check_admin(request)
	c = await Comment.find(id)
	if not c:
	 	raise APIResourceNotFoundError('Comment')
	await c.remove()
	return dict(id=id)


@get("/aboutme")
def about_me():
	return {
		"__template__":"about_me.html"

	}

	  